package se.study.algorithm;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * @Author: tiger
 * @Date:2018/5/21
 * @Description:加密算法联系
 */
public class MessageDigestAlgorithm {
    public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
        md5Test();


    }

    /**
     * MD5算法具有以下特点：
     * <p>
     * 1、压缩性：任意长度的数据，算出的MD5值长度都是固定的。
     * 2、容易计算：从原数据计算出MD5值很容易。
     * 3、抗修改性：对原数据进行任何改动，哪怕只修改1个字节，所得到的MD5值都有很大区别。
     * 4、弱抗碰撞：已知原数据和其MD5值，想找到一个具有相同MD5值的数据（即伪造数据）是非常困难的。
     * 5、强抗碰撞：想找到两个不同的数据，使它们具有相同的MD5值，是非常困难的。
     * MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被”压缩”成一种保密的格式（就是把一个任意长度的字节串变换成一定长的十六进制数字串）。除了MD5以外，其中比较有名的还有sha-1、RIPEMD以及Haval等。
     * </p>
     * 应用：由于MD5单向，MD5将任意长度的"字节串"变换成一个128bit的大整数，并且它是一个不可逆的字符串变换算法，换句话说就是，即使你看到源程序和算法描述，也无法将一个MD5的值变换回原始的字符串。可以用作数字签名：防篡改。
     */
    private static void md5Test() throws NoSuchAlgorithmException {
        String before = "tiger123456";
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        byte[] bytes = before.getBytes();
        byte[] digest = md5.digest(bytes);

        System.out.println("字符串：" + new String(digest));
        BigInteger after = new BigInteger(digest);

        System.out.println("10进制：" + after);

        String hex = after.toString(16);

        System.out.println("转为16进制：" + hex);
    }

    /**
     * BASE64的加密解密是双向的，可以求反解.严格地说，属于编码格式，而非加密算法
     * 主要就是BASE64Encoder、BASE64Decoder两个类，我们只需要知道使用对应的方法即可。
     * 另，BASE加密后产生的字节位数是8的倍数，如果不够位数以=符号填充。
     * 常见于邮件、http加密，截取http信息，你就会发现登录操作的用户名、密码字段通过BASE64加密的。
     */
    private static void base64Test() throws IOException {
        String pd = "tiger123321";
        BASE64Encoder base64Encoder = new BASE64Encoder();

        String encode = base64Encoder.encode(pd.getBytes());
        System.out.println(encode);

        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] bytes = base64Decoder.decodeBuffer(encode);
        String de = new String(bytes);
        System.out.println(de);
    }

    /**
     * 标准的Base64并不适合直接放在URL里传输，因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式，而这些“%”号在存入数据库时还需要再进行转换，因为ANSI SQL中已将“%”号用作通配符。
     * 为解决此问题，可采用一种用于URL的改进Base64编码，它不仅在末尾去掉填充的'='号，并将标准Base64中的“+”和“/”分别改成了“-”和“_”，这样就免去了在URL编解码和数据库存储时所要作的转换，避免了编码信息长度在此过程中的增加，并统一了数据库、表单等处对象标识符的格式。
     */
    private static void base64UrlTest() {
        String before = "https://baike.baidu.com/item/base64";
        Base64.Encoder urlEncoder = Base64.getUrlEncoder();
        String after = urlEncoder.encodeToString(before.getBytes());
        System.out.println("加密后:" + after);

        byte[] decode = Base64.getUrlDecoder().decode(after);
        String deStr = new String(decode);
        System.out.println("解密后:" + deStr);
    }
}
